<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>模仿example - 流动的线</title>
  <style>
    html, body {
      margin: 0;
      height: 100%;
    }
    canvas {
      display: block;
    }
  </style>
  <script src="./lib/three.js/build/three.min.js"></script>
  <script src="./lib/three.js/examples/js/controls/OrbitControls.js"></script>
  <script type="x-shader/x-vertex" id="vertexshader">

  attribute float size;
  attribute vec3 customColor;

  varying vec3 vColor;

  void main() {

    vColor = customColor;

    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );

    gl_PointSize = size * ( 300.0 / -mvPosition.z );

    gl_Position = projectionMatrix * mvPosition;

  }

  </script>
  <script type="x-shader/x-fragment" id="fragmentshader">
  uniform vec3 color;
  uniform sampler2D pointTexture;

  varying vec3 vColor;

  void main() {

    gl_FragColor = vec4( color * vColor, 1.0 );
    gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord );

  }
  </script>
</head>
<body>
  <script type="module">

    var WIDTH = window.innerWidth;
    var HEIGHT = window.innerHeight;

    var camera = new THREE.PerspectiveCamera(40, WIDTH / HEIGHT, 1, 10000);
    camera.position.z = 200;

    var scene = new THREE.Scene();
    
    var path = new THREE.Path();

    path.lineTo( -50, 40 );
    path.quadraticCurveTo( -50, 50, -40, 50 );
    path.lineTo( 40, 50 );
    path.quadraticCurveTo( 50, 50, 50, 40 );
    path.lineTo( 50, -40 );
    path.quadraticCurveTo( 50, -50, 40, -50 );
    path.lineTo( -40, -50 );
    path.quadraticCurveTo( -50, -50, -50, -40  );

    var points = path.getPoints(20)
    
    points = points.slice(1)

    var _points = []
    for(let i = 0; i < 4; i++) {
      for(let j = -39; j < 40; j++) {
        let x, y;
        if (i == 0) {
          x = j
          y = 50
        } else if (i == 1) {
          x = 50
          y = -j
        } else if (i == 2) {
          x = -j
          y = -50
        } else {
          x = -50
          y = j
        }
        _points.push(new THREE.Vector2(x, y))
      }
    }

    var count = {
      r: points.length / 4,
      l: _points.length / 4
    }

    var result = []
    for(let i = 1; i < 5; i++) {
      let arr1 = points.slice(count.r * (i - 1), count.r * i)
      let arr2 = _points.slice(count.l * (i - 1), count.l * i)
      result = result.concat(arr1, arr2)
    }
    
    var colors = new Float32Array(result.length * 3);
    var sizes = new Float32Array(result.length);
    for(let i = 0; i < result.length; i++) {
      let color;
      let type = parseInt(i / 10)
      if (type % 2 == 0) {
        let d = parseInt(255 * (i % 10) / 10)
        color = new THREE.Color("rgb(" + d + ", " + d + ", 0)")
      } else {
        color = new THREE.Color("rgb(0, 0, 0)")
      }
      color.toArray(colors, i * 3)
      sizes[i] = 3
    }

    var geometry = new THREE.BufferGeometry().setFromPoints( result );
    geometry.addAttribute('customColor', new THREE.BufferAttribute(colors, 3));
    geometry.addAttribute('size', new THREE.BufferAttribute(sizes, 1));

    var material = new THREE.ShaderMaterial({
      uniforms: {
        color: { value: new THREE.Color(0xf0ffff) },
        pointTexture: { value: new THREE.TextureLoader().load("images/water.jpg") }
      },
      vertexShader: document.getElementById('vertexshader').textContent,
      fragmentShader: document.getElementById('fragmentshader').textContent,
      depthTest: false,
      depthWrite: false,
      transparent: true
    });

    let ring = new THREE.Points(geometry, material)

    scene.add( ring )

    // 初始化render
    var renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(WIDTH, HEIGHT);
    document.body.appendChild(renderer.domElement);
    
    // 初始化轨道控制器
    var controls = new THREE.OrbitControls(camera, renderer.domElement);

    // 绘制
    function animate() {
      requestAnimationFrame(animate);

      var geometry = ring.geometry;
      var attributes = geometry.attributes
      var arr = attributes.position.array.toString().split(",")
      var delArray = arr.splice(0, 3)
      var newArray = arr.concat(delArray)
      attributes.position.array = new Float32Array(newArray);
      attributes.position.needsUpdate = true
      
      renderer.render(scene, camera);
    }

    animate();
  </script>
</body>
</html>
